import { Device } from "@bidiao/framework";
import JSEncrypt from "jsencrypt";

import EncUtf8 from "crypto-js/enc-utf8";
import AES from "crypto-js/aes";
import SHA256 from "crypto-js/sha256";
import WordArray from "crypto-js/lib-typedarrays";
import EncBase64 from "crypto-js/enc-base64";
import EncHex from "crypto-js/enc-hex";

const apiHost = `https://192.168.30.125:7116/hhhh/`;

const pageStartTime = String(((Date.now() - Number(document.timeline.currentTime)) / 1000) >> 0);

async function encrypt(appId: string, data: string) {
  const config = await getConfig(appId);
  const key = WordArray.random(16); // 生成随机key
  const iv = EncBase64.parse(config.iv); // 生成随机iv
  return {
    key: rsaEncrypt(config.pubKey, key.toString(EncHex)), // 密钥使用 rsa 加密
    data: AES.encrypt(EncUtf8.parse(data), key, { iv }).toString(), // 数据使用AES加密
  };
}
function rsaEncrypt(pubKey: string, str: string) {
  const rsa = new JSEncrypt();
  rsa.setPublicKey(pubKey);

  return rsa.encrypt(str);
}
function sha256(str: string) {
  return SHA256(EncUtf8.parse(str)).toString(EncBase64);
}

let getConfigPromise: Promise<any>;

function getConfig(appId) {
  if (!getConfigPromise) {
    getConfigPromise = new Promise((resolve: (value: Response) => any, reject) => {
      const searchParams = new URLSearchParams();
      searchParams.set("appId", appId);
      searchParams.set(pageStartTime, Date.now().toString());
      const queryStr = searchParams.toString();

      request(`${apiHost}captcha/config?${queryStr}`).then(resolve, reject);
    }).then(res => res.json());
  }
  return getConfigPromise;
}

function request(url, options?: RequestInit) {
  const searchParams = new URL(url).searchParams;
  searchParams.sort();

  return fetch(url, {
    ...options,
    headers: {
      "x-bd-bid": Device.BrowserId,
      "x-bd-time": pageStartTime,
      "x-bd-hash": sha256(`${Device.BrowserId}?${searchParams}`),
      ...options?.headers,
    },
    mode: "cors",
    credentials: "include",
  });
}

export async function gen({ appId, type, scheme }) {
  await getConfig(appId);
  const searchParams = new URLSearchParams();
  searchParams.set("appId", appId);
  searchParams.set(pageStartTime, Date.now().toString());
  searchParams.set("type", type);
  searchParams.set("scheme", scheme);
  const queryStr = searchParams.toString();

  return await request(`${apiHost}captcha/gen?${queryStr}`);
}

export async function validate({ appId, trackData, token, startTime, completeTime, timeline }) {
  const searchParams = new URLSearchParams();
  searchParams.set("appId", appId);
  searchParams.set(pageStartTime, Date.now().toString());
  const queryStr = searchParams.toString();
  const encryptData = await encrypt(
    appId,
    JSON.stringify({
      input: trackData, // 用户输入的验证码
      startTime, // 刷新获取验证码的开始时间
      completeTime, // 输入验证码的完成后提交的时间
      timeline, // 组件加载完成的时间
    })
  );
  return await request(`${apiHost}captcha/validate?${queryStr}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      token,
      ...encryptData,
    }),
  });
}
